#include <mpi/mpi.h>
#include <stdio.h>
#define SIZE 16
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3

int main(int argc, char *argv[]) {
    int numtasks, rank, source, dest, outbuf, i,
        tag = 1,
        inbuf[4] =
            {
                MPI_PROC_NULL,
                MPI_PROC_NULL,
                MPI_PROC_NULL,
                MPI_PROC_NULL,
            },
        nbrs[4], dims[2] = {4, 4}, periods[2] = {0, 0}, reorder = 0, coords[2];

    MPI_Request reqs[8];
    MPI_Status stats[8];
    MPI_Comm cartcomm;  // required variable

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

    if (numtasks == SIZE) {
        // create cartesian virtual topology, get rank, coordinates, neighbor
        // ranks
        MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorder, &cartcomm);
        // 在通信器中创建一个二维(*dim = [4,4])的笛卡尔拓扑
        // 不允许头尾环状访问（*periods = [0,0]),
        // 不允许重新排列进程顺序(reorder = 0)
        // 到新的笛卡尔拓扑通信器中。
        MPI_Comm_rank(cartcomm, &rank);
        MPI_Cart_coords(cartcomm, rank, 2, coords);
        // 将rank转换为2维的拓扑下标数组.
        MPI_Cart_shift(cartcomm, 0, 1, &nbrs[UP], &nbrs[DOWN]);
        MPI_Cart_shift(cartcomm, 1, 1, &nbrs[LEFT], &nbrs[RIGHT]);
        // 在通信器内找邻居，维度、双向的步长.

        printf("rank= %d coords= %d %d  neighbors(u,d,l,r)= %d %d %d %d\n",
               rank, coords[0], coords[1], nbrs[UP], nbrs[DOWN], nbrs[LEFT],
               nbrs[RIGHT]);

        outbuf = rank;

        // exchange data (rank) with 4 neighbors
        for (i = 0; i < 4; i++) {
            dest = nbrs[i];
            source = nbrs[i];
            MPI_Isend(&outbuf, 1, MPI_INT, dest, tag, MPI_COMM_WORLD, &reqs[i]);
            MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag, MPI_COMM_WORLD,
                      &reqs[i + 4]);
        }

        MPI_Waitall(8, reqs, stats);

        printf("rank= %d                  inbuf(u,d,l,r)= %d %d %d %d\n", rank,
               inbuf[UP], inbuf[DOWN], inbuf[LEFT], inbuf[RIGHT]);
    } else
        printf("Must specify %d processors. Terminating.\n", SIZE);

    MPI_Finalize();
}
